package br.ufpb.di.ppgi.apresentacao.controllers;

import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.validator.Hibernate;
import br.com.caelum.vraptor.validator.ValidationMessage;
import br.com.caelum.vraptor.view.Results;
import br.com.simtecnologia.access.controll.annotation.ControlledResource;
import br.com.simtecnologia.access.controll.role.Roles;
import br.ufpb.di.ppgi.negocio.ServiceLocator;
import br.ufpb.di.ppgi.negocio.modelo.aluno.Aluno;
import br.ufpb.di.ppgi.negocio.modelo.professorExterno.ProfessorExterno;
import br.ufpb.di.ppgi.negocio.modelo.proposta.LinhasDePesquisa;
import br.ufpb.di.ppgi.negocio.modelo.usuario.Usuario;
import br.ufpb.di.ppgi.negocio.modelo.usuario.UsuarioRole;
import br.ufpb.di.ppgi.negocio.modelo.usuario.UsuarioSessionInfo;
import br.ufpb.di.ppgi.persistencia.pagination.ListaPaginada;
import br.ufpb.di.ppgi.persistencia.transaction.TransactionScoped;

@Path("/admin/cadastramentos/")
@ControlledResource
@Roles({"SECRETARIO"})
public class CadastramentosRestrictController extends AbstractController {
	
	private ServiceLocator serviceLocator;
	private UsuarioSessionInfo usuarioInfo;

	public CadastramentosRestrictController(Result result, Validator validator,
			ServiceLocator services, UsuarioSessionInfo usuarioInfo) {
		super(result, validator, services);
		
		this.serviceLocator = services;
		this.usuarioInfo = usuarioInfo;
	}

	@Get
	@Path("")
	public void index() {
	}
	
	@Path("alunos")
	public void listarAluno(String keyword,Integer page) {
		page = page == null || page < 0 ? 1 : page;
		keyword  = keyword == null ? "" : keyword.trim();
		
		String base = "admin/cadastramentos/alunos?"+(keyword.isEmpty() ? "key="+keyword+"&" : "")+"page=";
		ListaPaginada<Aluno> listaPaginada = serviceLocator.forAluno().filtrarPaginando(keyword,page,base);
		if (listaPaginada.getQtdPaginas() < page) {
			page = listaPaginada.getQtdPaginas();
			listaPaginada = serviceLocator.forAluno().filtrarPaginando(keyword,page,base);
		}
			
   		result.include("listaPaginada", listaPaginada.setMaximoDePaginas(5));
   		result.include("alunos", listaPaginada.getLista());
	}
	
	@Path("usuarios")
	public void listarUsuario(String keyword,Integer page) {
		page = page == null || page < 0 ? 1 : page;
		keyword  = keyword == null ? "" : keyword.trim();
		
		String base = "admin/cadastramentos/usuarios?"+(keyword.isEmpty() ? "key="+keyword+"&" : "")+"page=";
		ListaPaginada<Usuario> listaPaginada = serviceLocator.forUsuario().filtrarPaginando(keyword,page,base);
		if (listaPaginada.getQtdPaginas() < page) {
			page = listaPaginada.getQtdPaginas();
			listaPaginada = serviceLocator.forUsuario().filtrarPaginando(keyword,page,base);
		}
			
   		result.include("listaPaginada", listaPaginada.setMaximoDePaginas(5));
   		result.include("usuarios", listaPaginada.getLista());
	}
	
	@Path("professoresExternos")
	public void listarProfessorExterno(String keyword,Integer page) {
		page = page == null || page < 0 ? 1 : page;
		keyword  = keyword == null ? "" : keyword.trim();
		
		String base = "admin/cadastramentos/professoresExternos?"+(keyword.isEmpty() ? "key="+keyword+"&" : "")+"page=";
		ListaPaginada<ProfessorExterno> listaPaginada = serviceLocator.forProfessorExterno().filtrarPaginando(keyword,page,base);
		if (listaPaginada.getQtdPaginas() < page) {
			page = listaPaginada.getQtdPaginas();
			listaPaginada = serviceLocator.forProfessorExterno().filtrarPaginando(keyword,page,base);
		}
			
   		result.include("listaPaginada", listaPaginada.setMaximoDePaginas(5));
   		result.include("externos", listaPaginada.getLista());		
	}	
	
	@Get
	@Path({"editarAluno-{id}","inserirAluno"})
	public void formAluno(Long id) {
		result.include("professores", serviceLocator.forUsuario().listarProfessores());
		result.include("linhas", LinhasDePesquisa.asList());

		if (id != null)
			result.include("aluno", serviceLocator.forAluno().buscar(id));
		
	}
	
	@Get
	@Path({"editarUsuario-{id}","inserirUsuario"})
	public void formUsuario(Long id) {
		result.include("roles", UsuarioRole.asList());
		
		if (id != null)
			result.include("usuario", serviceLocator.forUsuario().buscar(id));
		
	}
	
	@Get
	@Path({"editarProfExterno-{id}","inserirProfExterno"})
	public void formProfExterno(Long id) {
		if (id != null)
			result.include("profExterno", serviceLocator.forProfessorExterno().buscar(id));
	}
	
	@Post
	@Path("salvarAluno")
	@TransactionScoped
	public void persistirAluno(Aluno aluno) {
		// Se nao tiver escolhido orientado/co-orientado (id = null), tem que nullar a referencia ao objeto, senao temos uma excecao 
		// object references an unsaved transient instance - save the transient instance before flushing
		// (paranamer =[ )

		if (aluno.getOrientador() != null && aluno.getOrientador().getId()== null)
			aluno.setOrientador(null);
		
		if (aluno.getCo_orientador() != null && aluno.getCo_orientador().getId()== null)
			aluno.setCo_orientador(null);
			
		validator.addAll(Hibernate.validate(aluno));
		validator.onErrorUse(Results.logic()).forwardTo(getClass()).formAluno(null);
		
		//checa duplicidade de cpf
		Aluno fetched = serviceLocator.forAluno().findByCPF(aluno.getCpf());
		
		if (aluno.getId() != null) {
			//SE JA HOUVER ALGUM ALUNO CADASTRADO COM O CPF INFORMADO, E Q NAO SEJA O ALUNO SENDO EDITADO
			if (fetched != null && !fetched.equals(aluno)) {
				resultIncludeErroValidacaoCPF("aluno",aluno);
				validator.onErrorUse(Results.logic()).forwardTo(getClass()).formAluno(null);
			}
			
			serviceLocator.forAluno().atualizar(aluno);
		} else {
			if (fetched != null) {
				resultIncludeErroValidacaoCPF("aluno",aluno);
				validator.onErrorUse(Results.logic()).forwardTo(getClass()).formAluno(null);
			}
			serviceLocator.forAluno().adicionar(aluno);
		}
		
		result.redirectTo(this).index();
	}

	
	@Post
	@Path("salvarUsuario")
	@TransactionScoped
	public void persistirUsuario(Usuario usuario) {

		if( usuario.getId() != null ){
			Usuario temp = serviceLocator.forUsuario().buscar(usuario.getId());
			if( temp != null )
				usuario.setSenha( temp.getSenha() );
		}
			
		validator.addAll(Hibernate.validate(usuario));
		validator.onErrorUse(Results.logic()).forwardTo(getClass()).formUsuario(usuario.getId());
		
		//checa duplicidade de cpf
		Usuario fetched = serviceLocator.forUsuario().findByCPF(usuario.getCpf());
		
		if (usuario.getId() != null) {
			if (fetched != null && !fetched.equals(usuario)) {
				resultIncludeErroValidacaoCPF("usuario",usuario);
				validator.onErrorUse(Results.logic()).forwardTo(getClass()).formUsuario(null);
			}
			serviceLocator.forUsuario().atualizar(usuario);			
		} else {
			if (fetched != null) {
				resultIncludeErroValidacaoCPF("usuario",usuario);
				validator.onErrorUse(Results.logic()).forwardTo(getClass()).formUsuario(null);
			}
			serviceLocator.forUsuario().adicionar(usuario);
		}
		
		result.redirectTo(this).index();
	}
	
	@Post
	@Path("salvarProfExterno")
	@TransactionScoped
	public void persistirProfExterno(ProfessorExterno profExterno) {
		validator.addAll(Hibernate.validate(profExterno));
		validator.onErrorUse(Results.logic()).forwardTo(getClass()).formProfExterno(profExterno.getId());
		
		//checa duplicidade de cpf
		ProfessorExterno fetched = serviceLocator.forProfessorExterno().findByCPF(profExterno.getCpf());
		
		if (profExterno.getId() != null) {
			//SE JA HOUVER ALGUM ProfessorExterno CADASTRADO COM O CPF INFORMADO, E Q NAO SEJA O ALUNO SENDO EDITADO			
			if (fetched != null && !fetched.equals(profExterno)) {
				resultIncludeErroValidacaoCPF("profExterno",profExterno);
				validator.onErrorUse(Results.logic()).forwardTo(getClass()).formProfExterno(null);
			}
			serviceLocator.forProfessorExterno().atualizar(profExterno);			
		} else {
			if (fetched != null) {
				resultIncludeErroValidacaoCPF("profExterno",profExterno);
				validator.onErrorUse(Results.logic()).forwardTo(getClass()).formProfExterno(null);
			}
			serviceLocator.forProfessorExterno().adicionar(profExterno);
		}
		
		result.redirectTo(this).index();
	}
	
	@Post
	@Get
	@Path("removerUsuario-{id}")
	@TransactionScoped
	public void removerUsuario(Long id) {
		Usuario usuario = serviceLocator.forUsuario().buscar(id);
		
		if( usuario != null ){
			
			if (usuario.getRole() == UsuarioRole.SU) {
				validator.add(new ValidationMessage(
						"Nao é possivel apagar um super-usuario.",
						"usuario"));
				return;
			}
			
			if (usuario == usuarioInfo.getUsuario()) {
				validator.add(new ValidationMessage(
						"Nao é possivel apagar seu próprio usuário.",
						"usuario"));
				return;
			}			
			
			if (id != null)
				serviceLocator.forUsuario().apagar(id);
			
		}
		
		result.redirectTo(this).index();
	}
	
	@Get
	@Path("removerAluno-{id}")
	@TransactionScoped
	public void removerAluno(Long id) {
		if (id != null)
			serviceLocator.forAluno().apagar(id);
		
		result.redirectTo(this).index();
	}

	@Get
	@Path("removerProfExterno-{id}")
	@TransactionScoped
	public void removerProfExterno(Long id) {
		if (id != null)
			serviceLocator.forProfessorExterno().apagar(id);
		
		result.redirectTo(this).index();
	}
	
	@Get
	@Path("validaCPFUsuario")
	public void validaCPFUsuario(String cpf,Long id) {
		boolean existe = false;
		
		if(cpf != null) {
			Usuario u = serviceLocator.forUsuario().findByCPF(cpf);
			
			if (u != null)
				existe = id == null ? true : !id.equals(u.getId());
		}
		
		result.use(Results.json()).from(existe).serialize();
	}

	@Get
	@Path("validaCPFAluno")
	public void validaCPFAluno(String cpf,Long id) {
		boolean existe = false;
		
		if(cpf != null) {
			Aluno u = serviceLocator.forAluno().findByCPF(cpf);
			
			if (u != null)
				existe = id == null ? true : !id.equals(u.getId());
		}
		
		result.use(Results.json()).from(existe).serialize();
	}

	@Get
	@Path("validaCPFProfessorExterno")
	public void validaCPFProfessorExterno(String cpf,Long id) {
		boolean existe = false;
		
		if(cpf != null) {
			ProfessorExterno u = serviceLocator.forProfessorExterno().findByCPF(cpf);
			
			if (u != null)
				existe = id == null ? true : !id.equals(u.getId());
		}
		
		result.use(Results.json()).from(existe).serialize();
	}
	

	private void resultIncludeErroValidacaoCPF(String string, Object obj) {
		result.include(string, obj);
		validator.add(new ValidationMessage("Este CPF já esta cadastrado.", "error"));
	}
}
